import os
import json
import argparse
import re
from datetime import datetime
from urllib.parse import urlparse, parse_qs, unquote_plus


class HarParser:
    def __init__(self):
        self.api_endpoints = {}
        self.logger = self._setup_logger()
        self.duplicate_count = 0

    def _setup_logger(self):
        import logging
        logger = logging.getLogger("HarParser")
        logger.setLevel(logging.INFO)
        handler = logging.StreamHandler()
        formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
        handler.setFormatter(formatter)
        logger.addHandler(handler)
        return logger

    def parse_har_file(self, har_file_path):
        """解析HAR文件"""
        try:
            self.logger.info(f"开始解析HAR文件：{har_file_path}")
            if not os.path.exists(har_file_path):
                self.logger.error(f"HAR文件不存在：{har_file_path}")
                return

            with open(har_file_path, 'r', encoding='utf-8-sig') as f:
                har_data = json.load(f)

            entries = har_data.get('log', {}).get('entries', [])
            self.logger.info(f"发现 {len(entries)} 个请求条目")

            for entry in entries:
                request = entry.get('request', {})
                response = entry.get('response', {})

                url = request.get('url', '')
                parsed_url = urlparse(url)
                path = parsed_url.path
                method = request.get('method', 'GET')

                # 解析请求头并检查是否需要token
                headers = {h.get('name', '').lower(): h.get('value', '') for h in request.get('headers', [])}
                requires_token = 'authorization' in headers or 'token' in headers

                # 解析查询参数（GET请求）
                query_params = parse_qs(parsed_url.query)

                # 解析请求体参数（POST/PUT请求）
                request_params = {}
                post_data = request.get('postData', {})
                post_mimeType = post_data.get('mimeType', '')
                post_params = post_data.get('params', [])

                if post_params:
                    for param in post_params:
                        name = param.get('name', '')
                        value = param.get('value', '')
                        if name:
                            request_params[name] = value
                elif 'text' in post_data:
                    post_text = post_data.get('text', '')
                    if post_text and 'application/json' in post_mimeType:
                        try:
                            json_data = json.loads(post_text)
                            self._flatten_json_params(json_data, request_params)
                        except json.JSONDecodeError:
                            self.logger.warning(f"无法解析JSON请求体: {post_text[:100]}...")
                            request_params = {"raw_body": post_text[:200]}

                # 生成请求签名
                request_signature = self._generate_request_signature(method, path, headers, request_params)

                # 解析响应
                status = response.get('status', 0)
                response_body = response.get('content', {}).get('text', '')

                # 检查是否为重复请求
                if self._is_duplicate_request(request_signature, status, response_body):
                    self.duplicate_count += 1
                    self.logger.debug(f"重复请求，已过滤: {method} {path}")
                    continue

                # 生成端点标识
                endpoint_key = f"{method} {path}"

                if endpoint_key not in self.api_endpoints:
                    self.api_endpoints[endpoint_key] = {
                        'method': method,
                        'path': path,
                        'description': '',
                        'query_params': query_params,
                        'request_params': request_params,
                        'headers': headers,
                        'requires_token': requires_token,  # 新增：是否需要token
                        'request_body_type': post_mimeType,
                        'responses': []
                    }

                self.api_endpoints[endpoint_key]['responses'].append({
                    'status': status,
                    'body': response_body,
                    'content_type': response.get('content', {}).get('mimeType', ''),
                    'signature': request_signature
                })

            self.logger.info(f"成功解析 {len(self.api_endpoints)} 个API端点")
            self.logger.info(f"过滤了 {self.duplicate_count} 个重复请求")

        except Exception as e:
            self.logger.error(f"解析HAR文件时出错：{str(e)}", exc_info=True)

    def _flatten_json_params(self, json_obj, params, parent_key=''):
        """递归展平JSON参数"""
        if isinstance(json_obj, dict):
            for key, value in json_obj.items():
                new_key = f"{parent_key}.{key}" if parent_key else key
                self._flatten_json_params(value, params, new_key)
        elif isinstance(json_obj, list):
            for i, value in enumerate(json_obj):
                new_key = f"{parent_key}[{i}]" if parent_key else f"[{i}]"
                self._flatten_json_params(value, params, new_key)
        else:
            params[parent_key] = str(json_obj)

    def _generate_request_signature(self, method, path, headers, params):
        """生成请求签名"""
        param_str = '&'.join([f"{k}={v}" for k, v in params.items()][:5])
        content_type = headers.get('content-type', '')
        return f"{method}|{path}|{content_type}|{param_str}"

    def _is_duplicate_request(self, signature, status_code, response_body):
        """判断是否为重复请求"""
        for endpoint in self.api_endpoints.values():
            for resp in endpoint['responses']:
                if resp.get('signature') == signature:
                    if resp['status'] == status_code and self._similar_response_bodies(resp['body'], response_body):
                        return True
        return False

    def _similar_response_bodies(self, body1, body2, threshold=0.9):
        """判断两个响应体是否相似"""
        if not body1 or not body2:
            return body1 == body2

        if body1.startswith(('{', '[')) and body2.startswith(('{', '[')):
            return (
                    abs(len(body1) - len(body2)) / max(len(body1), len(body2)) < 0.3 and
                    body1[:100] == body2[:100]
            )

        return body1[:50] == body2[:50]

    def generate_markdown_docs(self, output_file=None):
        """生成Markdown文档（改进：移除参数类型，增加token说明）"""
        markdown = "# API接口文档\n"
        markdown += f"生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n"
        markdown += f"总接口数: {len(self.api_endpoints)}\n"
        markdown += f"过滤的重复请求数: {self.duplicate_count}\n\n"

        # 添加全局token说明
        token_endpoints = [e for e in self.api_endpoints.values() if e['requires_token']]
        if token_endpoints:
            markdown += "## 认证说明\n"
            markdown += "以下接口需要在请求头中包含认证信息：\n\n"
            for endpoint in token_endpoints:
                markdown += f"- [{endpoint['method']} {endpoint['path']}](#{endpoint['method'].lower()}-{endpoint['path'].replace('/', '-').replace('{', '').replace('}', '')})\n"
            markdown += "\n请在请求头中添加 `Authorization: Bearer <token>` 字段进行认证\n\n"
            markdown += "---\n\n"

        endpoints = sorted(self.api_endpoints.values(), key=lambda x: x['path'])
        for endpoint in endpoints:
            method = endpoint['method']
            path = endpoint['path']

            # 为每个接口添加锚点
            anchor = f"{method.lower()}-{path.replace('/', '-').replace('{', '').replace('}', '')}"
            markdown += f"<a name=\"{anchor}\"></a>\n"

            markdown += f"## {method} {path}\n\n"

            # 添加token说明
            if endpoint['requires_token']:
                markdown += "**注意：此接口需要认证token**\n\n"

            # GET请求参数说明（移除类型列）
            if endpoint['query_params']:
                markdown += "### GET请求参数\n"
                markdown += "| 参数名 | 是否必选 | 描述 | 示例 |\n"
                markdown += "|--------|----------|------|------|\n"
                for param, values in endpoint['query_params'].items():
                    example = values[0] if values and len(values) > 0 else ""
                    markdown += f"| {param} | 否 | | {example} |\n"
                markdown += "\n"

            # POST请求参数说明（移除类型列）
            if endpoint['request_params']:
                markdown += "### POST请求参数\n"
                markdown += "| 参数名 | 是否必选 | 描述 | 示例 |\n"
                markdown += "|--------|----------|------|------|\n"

                sorted_params = sorted(endpoint['request_params'].items(),
                                       key=lambda x: (0, x[0]) if '.' not in x[0] and '[' not in x[0] else (1, x[0]))

                for param, value in sorted_params:
                    display_name = param.replace('.', ' → ').replace('[', '[').replace(']', ']')
                    markdown += f"| {display_name} | 否 | | {value} |\n"
                markdown += "\n"

            # 请求头
            if endpoint['headers']:
                markdown += "### 请求头\n"
                markdown += "| 头信息 | 值 |\n|--------|-----|\n"
                for k, v in endpoint['headers'].items():
                    if k.lower() not in ['authorization', 'cookie']:  # 过滤敏感信息
                        markdown += f"| {k} | {v} |\n"
                if endpoint['requires_token']:
                    markdown += "| Authorization | Bearer <token> |\n"  # 添加token说明
                markdown += "\n"

            # 响应
            if endpoint['responses']:
                markdown += "### 响应\n"
                responses = sorted(endpoint['responses'], key=lambda x: int(x['status']))
                for resp in responses:
                    markdown += f"#### 状态码: {resp['status']}\n"
                    markdown += f"**类型**: {resp['content_type']}\n\n"

                    body = resp['body']
                    if len(body) > 3000:
                        body = body[:3000] + "...\n\n（响应体过长，已截断）"

                    if resp['content_type'].startswith('application/json'):
                        try:
                            json_obj = json.loads(body)
                            body = json.dumps(json_obj, indent=2, ensure_ascii=False)
                            markdown += "```json\n" + body + "\n```\n\n"
                        except:
                            markdown += "```\n" + body + "\n```\n\n"
                    else:
                        markdown += "```\n" + body + "\n```\n\n"

            markdown += "---\n\n"

        if output_file:
            with open(output_file, 'w', encoding='utf-8') as f:
                f.write(markdown)
            self.logger.info(f"文档已保存到 {output_file}")
        else:
            print(markdown)
        return markdown


def main():
    parser = argparse.ArgumentParser(description='从HAR文件生成API文档')
    parser.add_argument('input_file', help='HAR文件路径')
    parser.add_argument('-o', '--output', help='输出Markdown路径')
    args = parser.parse_args()

    if not args.input_file.lower().endswith('.har'):
        print("错误：请提供HAR文件")
        return

    parser = HarParser()
    parser.parse_har_file(args.input_file)

    if parser.api_endpoints:
        parser.generate_markdown_docs(args.output)
    else:
        print("未能从HAR文件中提取有效接口信息")


if __name__ == "__main__":
    main()